# -* coding= utf-8 -*-
from datetime import time, datetime, timedelta

class ConditionResult:

    def __init__(self, result=False, reason="----", reason_code="----"):
        self._result = result
        self._reason = reason
        self._reason_code = reason_code

    @property
    def result(self):
        return self._result

    @result.setter
    def result(self, result):
        self._result = result

    @property
    def reason(self):
        return self._reason

    @reason.setter
    def reason(self, reason):
        self._reason = reason

    @property
    def reason_code(self):
        return self._reason_code

    @reason_code.setter
    def reason_code(self, reason_code):
        self._reason_code = reason_code


# ==============================================
# KDJ
# 指标说明：
# KDJ，其综合动量观念、强弱指标及移动平均线的优点，早年应用在期货投资方面，功能颇为显著，目前为股市中最常被使用的指标之一。
# 买卖原则：
# 1.K线由右边向下交叉D值做卖，K线由右边向上交叉D值做买。
# 2.高档连续二次向下交叉确认跌势，低挡连续二次向上交叉确认涨势。
# 3.D值<20%超卖，D值>80%超买，J>100%超买，J<10%超卖。
# 4.KD值于50%左右徘徊或交叉时，无意义。
# 5.投机性太强的个股不适用。
# 6.可观察KD值同股价的背离，以确认高低点。
# ==============================================
# MACD
# 指标说明：
# MACD指数平滑异同移动平均线为两条长、短的平滑平均线。
# 其买卖原则为：
# 1.DIFF、DEA均为正，DIFF向上突破DEA，买入信号参考。
# 2.DIFF、DEA均为负，DIFF向下跌破DEA，卖出信号参考。
# 3.DEA线与K线发生背离，行情可能出现反转信号。
# 4.分析MACD柱状线，由红变绿(正变负)，卖出信号参考；由绿变红，买入信号参考。
# ===============================================
# BIAS
# 指标说明：
# 乖离率表现个股当日收盘价与移动平均线之间的差距。正的乖离率愈大，表示短期获利愈大，则获利回吐的可能性愈高；负的乖离率愈大，则空头回补的可能性愈高。
# 按个股收盘价与不同天数的平均价之间的差距，可绘制不同的BIAS线。
# ===============================================
# CCI
# 指标说明：
# 按市场的通行的标准，CCI指标的运行区间可分为三大类：大于﹢100、小于-100和﹢100——-100之间。　　
# 1.当CCI＞﹢100时，表明股价已经进入非常态区间——超买区间，股价的异动现象应多加关注。　　
# 2.当CCI＜-100时，表明股价已经进入另一个非常态区间——超卖区间，投资者可以逢低吸纳股票。　　
# 3.当CCI介于﹢100——-100之间时表明股价处于窄幅振荡整理的区间——常态区间，投资者应以观望为主。
# =========================================================================
# ADTM
# 原理：
#     1、如果开盘价<=昨日开盘价，DTM=0，如果开盘价>昨日开盘价，DTM=(最高价-开盘价)和(开盘价-昨日开盘价)的较大值。
#     2、如果开盘价>=昨日开盘价，DBM=0，如果开盘价<昨日开盘价，DBM=(开盘价-最低价)和（昨日开盘价-开盘价）的较大值
#     3、STM=DTM在N个周期内的和。
#     4、SBM=DBM在N个周期内的和。
#     5、如果STM>SBM,ADTM=(STM-SBM)/STM,如果STM=SBM,ADTM=0,如果STM<SBM,ADTM=(STM-SBM)/SBM。
#     6、ADTM MA为ADTM在某周期内的简单移动平均。
# 用法：
#     1、该指标在+1到-1之间波动；
#     2、低于-0.5时为很好的买入点,高于+0.5时需注意风险。


class AdviseX:
    Up = "↑"
    Weak_Up = "↗"

    Weak_Down = "↘"
    Down = "↓"
    Unknown = "～"
    Trend_Length = 5
    Bottom_Turn = "︶"
    Top_Turn = "︵"


class Advise:
    direction = AdviseX.Unknown
    degree = 0
    last_degree = 0
    last_degree2 = 0
    last_degree_rise = 0
    info = 0
    reason = None
    volume = None
    close = None
    ma_turn = None
    ma_turn_distance = None
    diff_turn = None
    diff_turn_distance = None
    last_ma_turn = None
    cant_up = False
    cant_down = False
    ma05_trend = False
    ma10_trend = False
    ma20_trend = False
    ma30_trend = False
    ma60_trend = False
    ma120_trend = False
    ma240_trend = False
    ma_distance = 0
    rise = 0
    ma5_m10 = None
    last_over_points = 0
    over_points = 0
    turn_points = 0
    cross_points = 0
    long_trend = None
    short_trend = None
    short_target = None
    temp_target = None


class CrossX:
    # 交叉
    Jx = "金叉"
    Sx = "死叉"
    Unknown = "～"
    # 挡位
    High = "高档"
    Low = "抵挡"

    # 与K线背离
    Leave = "背离"
    No_Leave = "不背离"


class CrossSignal:
    cross = CrossX.Unknown
    twice = False
    position = None
    leave_k = None
    # 金叉、死叉的趋势
    trend = None


class OverX:
    # 超 +-100
    Oversold = "超卖"
    Overbought = "超买"
    OverNormal = "未超"
    # 超 +-200
    Supersold = "超卖x2"
    Superbought = "超买x2"
    SuperNormal = "未超x2"


class OverSignal:
    over = None
    over2x = None
    turn = None
    m_turn = None
    twice = False
    value: 0.0
    direction: AdviseX.Unknown
    degree: 0.0


class Common:
    running_time: None

    @staticmethod
    def after_mins(dt, mins):
        return (datetime.strptime(dt, "%Y-%m-%d %H:%M:%S") + timedelta(minutes=mins)).strftime("%Y-%m-%d %H:%M:%S")

    @staticmethod
    def get_turn(bar, has_top_turn, has_bottom_turn):
        turn_all = has_bottom_turn - has_top_turn
        turn_only = turn_all[turn_all != 0]
        if len(turn_only) > 0:
            distance = turn_all.index.codes[0][-1] - turn_only[-1:].index.codes[0][0]
            return AdviseX.Top_Turn if turn_only[-1] < 0 else AdviseX.Bottom_Turn if turn_only[-1] > 0 else AdviseX.Unknown, distance
        return AdviseX.Unknown, 999

    @staticmethod
    def get_last_direction(bar, series):
        return AdviseX.Up if series[-1] > series[-2] else AdviseX.Down if series[-1] < series[-2] else AdviseX.Unknown

    @staticmethod
    def turn_direction(bar, direction):
        return AdviseX.Down if direction == AdviseX.Up else AdviseX.Up if direction == AdviseX.Down else AdviseX.Unknown

    @staticmethod
    def has_bottom_turn(series):
        length = len(series)
        min_index = length - 2
        b2 = b3 = False
        # 最大值在倒数第二位置
        b1 = series.argmin() == min_index
        min_value = series[min_index]
        if b1:
            #          最后一个 大于 最小值
            b2 = series[-1] > min_value  # 即last_ma05
        if b2:
            #      最小值前面所有的值      大于   最小值,且前到后是从大到小
            b3 = ((series[:min_index + 1]).diff(-1).dropna() >= 0).all()
        # 三者都满足，此时更新开仓价为反弹最高点价格
        if b3:
            index = series.index[min_index][0]
            if type(index) == str:
                turn_time_value = index
            else:
                turn_time_value = index.value
            return turn_time_value
        return 0

    @staticmethod
    def has_top_turn(series):
        length = len(series)
        max_index = length - 2
        b2 = b3 = False
        # 最大值在倒数第二位置
        b1 = series.argmax() == max_index
        max_value = series[max_index]
        if b1:
            #          最后一个 小于 最大值
            b2 = series[-1] < max_value  # 即last_ma05
        if b2:
            #      最大值前面所有的值      小于   最大值，从前往后是 从小到大
            b3 = ((series[:max_index + 1]).diff(-1).dropna() <= 0).all()
        # 三者都满足，此时更新开仓价为反弹最高点价格
        if b3:
            index = series.index[max_index][0]
            if type(index) == str:
                turn_time_value = index
            else:
                turn_time_value = index.value
            return turn_time_value
        return 0
